package com.jazzautomation.ui; import org.apache.commons.io.input.Tailer; import org.apache.commons.io.input.TailerListener; import org.apache.commons.io.input.TailerListenerAdapter; import org.apache.commons.lang3.StringUtils; import java.io.File; import java.util.ArrayDeque; import java.util.Queue; import javax.swing.BoundedRangeModel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingWorker; /** * Runner for the log tailer - has to be done in the background so the UI is still responsive. * * <p>Yeah, it's threaded - let the JVM do the heavy lifting.</p> */ public class ProgressTailer extends SwingWorker<Object, Object> { public static final int PIXELS_PER_ROW = 18; public static final int DELAY_MILLIS = 250; private JTextArea outputTextArea; private String logsPath; private JScrollPane outputScrollPane; private Tailer tailer; private int maxSize; private Queue<String> queue = new ArrayDeque<>(25); // initial size public ProgressTailer(JTextArea outputTextArea, String logsPath, JScrollPane outputScrollPane) { this.outputTextArea = outputTextArea; this.logsPath = logsPath; this.outputScrollPane = outputScrollPane; } /** * We're in a loop, constantly getting the log. We remove any lines previously there before we started, then paste what's left into the text area. */ @Override protected Object doInBackground() throws Exception { File logFile = new File(logsPath); TailerListener listener = new MyTailerListener(); tailer = Tailer.create(logFile, listener, DELAY_MILLIS, true); return null; } public void stop() { tailer.stop(); } class MyTailerListener extends TailerListenerAdapter { public void handle(String line) { maxSize = outputTextArea.getSize().height / PIXELS_PER_ROW; // UI size could have changed // For now, never pop the queue - tail the entire new part of the log // while (queue.size() >= maxSize) // { // System.out.println("queue.size() [" + queue.size() + ']' + " >= maxSize[" + maxSize + ']'); // queue.remove(); // } queue.add(line); populateTextAreaFromQueue(); } private void populateTextAreaFromQueue() { StringBuilder sb = new StringBuilder(queue.size()); for (String line : queue) { sb.append(line).append('\n'); } String text = sb.toString(); text = StringUtils.removeEnd(text, "\n"); outputTextArea.setText(text); JScrollBar verticalScrollBar = outputScrollPane.getVerticalScrollBar(); BoundedRangeModel model = verticalScrollBar.getModel(); int maximum = model.getMaximum(); model.setValue(maximum); } } }